package com.study.common.transaction;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author yaojinshan
 * @version 1.0
 * @description: 分布式事务执行器
 * 注意：1.如果使用了dubbo服务 需要注意dubbo的重试机制 导致的多次回滚和 执行分布式事务
 * 2.建议 针对每次分布式事务 使用一个唯一标识 在redis中存储  解决并发的问题
 * @date 2019/5/31 13:59
 */
public class DistributedTransactionsExecutor {
    //分布式事务列表：将一个逻辑中所有要执行的分布式事务都存放进去
    public List<AbstarctDistributedTransaction> transactionsList = new ArrayList<>();
    //维护一个回退的线程池 用来异步回退
    private static ExecutorService rollbackThreadExecutors = Executors.newFixedThreadPool(10);

    /**
    　* @description: 返回执行器的 事务列表
    　* @author yaojinshan
    　* @date 2019/5/31 14:03
    　*/
    public List<AbstarctDistributedTransaction> getTransactionsList(){
        return  transactionsList;
    }

    public DistributedTransactionsExecutor() {

    }

    public DistributedTransactionsExecutor(List<AbstarctDistributedTransaction> transactionsList) {
        if (transactionsList != null) {
            this.transactionsList = transactionsList;
        }
    }

    /**
    　* @description:执行事务列表
    　* @author yaojinshan
    　* @date 2019/5/31 14:06
    　*/
    public void executeTransactions(){
        if (transactionsList == null || transactionsList.isEmpty()){
            return;
        }
        try {
            for (AbstarctDistributedTransaction transaction : this.transactionsList) {
                //事务执行成功 就修改其状态为成功 否则抛出异常
                if(transaction.execute()){
                    transaction.executeSuccess();
                }else{
                    throw new RuntimeException("分布式事务执行失败，回退事务！");
                }
            }
        }catch (Exception e){
            //收到异常后 打印异常信息 并回退
            e.printStackTrace();
        }finally {
            if(checkRollback()){
                rollbackThreadExecutors.execute(new RollBackThread(transactionsList));
            }
        }
    }
    /**
    　* @description: 检查是否需要回滚 ： 如果事务的 needRollBack 返回true 则需要回滚
    　* @author yaojinshan
    　* @date 2019/5/31 14:30
    　*/
    public boolean checkRollback(){
        for (AbstarctDistributedTransaction transaction:transactionsList) {
            if(transaction.needRollBack()){
                return true;
            }
        }
        return false;
    }
}
/**
　* @description: 回退线程类：做事务回滚
　* @author yaojinshan
　* @date 2019/5/31 14:27
　*/
class RollBackThread implements Runnable{
    private List<AbstarctDistributedTransaction> transactionsList;
    public RollBackThread(List<AbstarctDistributedTransaction> transactionsList) {
        this.transactionsList = transactionsList;
    }

    @Override
    public void run() {
        if(transactionsList == null ||  transactionsList.isEmpty()){
            return;
        }
        for (AbstarctDistributedTransaction transaction:transactionsList) {
            if(transaction.needRollBack()){
                transaction.rollback();
            }
        }
    }
}